#!/usr/bin/perl
use FindBin;
use lib "$FindBin::Bin/../lib/perl-lib/lib/perl5";
use lib "$FindBin::Bin/../lib";

use strict;
use JSON;
use Getopt::Long;
use POSIX;

use AutoExecUtils;

sub usage {
    my $pname = $FindBin::Script;

    print("$pname --backup 0|1 --hostname <Host name> --ip2hostnamemap <Node Ip to Host Name>\n");
    exit(1);
}

sub backup {
    my ($filePath)  = @_;
    my $dateTimeStr = strftime( "%Y%m%d-%H%M%S", localtime() );
    my $exitCode    = system(qq{cp "$filePath" "$filePath.$dateTimeStr"});
    return $exitCode;
}

sub main {
    my $reset      = 1;
    my $needBackup = 0;
    my $node;
    my $hostName;
    my $hostNameMapJson;

    GetOptions(
        'backup=i'         => \$needBackup,
        'reset=i'          => \$reset,
        'node=s'           => \$node,
        'hostname=s'       => \$hostName,
        'ip2hostnamemap=s' => \$hostNameMapJson
    );

    my $nodeInfo  = {};
    my $hasOptErr = 0;
    if ( not defined($node) ) {
        $node = $ENV{AUTOEXEC_NODE};
    }

    if ( not defined($node) or $node eq '' ) {
        $hasOptErr = 1;
    }
    else {
        $nodeInfo = from_json($node);
    }

    if ( $hasOptErr == 1 ) {
        usage();
    }

    my $filePath = '/etc/hosts';

    my $osType = ( uname() )[0];
    $osType =~ s/\s.*$//;
    if ( $osType eq 'Windows' ) {
        my $winDir = $ENV{WINDIR};
        $winDir =~ s/\\/\//g;
        $filePath = "$winDir/system32/drivers/etc/hosts";
    }

    my $hostNameMap;
    if ( defined($hostNameMapJson) and $hostNameMapJson ne '' ) {
        $hostNameMap = from_json($hostNameMapJson);
    }
    else {
        print("WARN: Ip to hostname map not provided, set hostname only, would not modify hosts config file.\n");
    }

    my $hasError   = 0;
    my $newContent = '';

    if ( $reset == 1 ) {
        my $fh = IO::File->new( $filePath, 'w' );
        if ( defined($fh) ) {
            print $fh ('');
            $fh->close();
            $newContent = "127.0.0.1\tlocalhost localhost.localdomain localhost4 localhost4.localdomain4\n" . "::1 \tlocalhost localhost.localdomain localhost6 localhost6.localdomain6\n";
        }
        else {
            $hasError = 1;
            print("ERROR: Can not write to file $filePath.\n");
            return $hasError;
        }
    }

    if ( defined($hostNameMap) ) {
        my $ip = $nodeInfo->{host};
        $hostName = $hostNameMap->{$ip};

        if ( not defined($hostName) or $hostName eq '' ) {
            $hasError = 1;
            print("ERROR: Can not find host in $hostNameMapJson for ip:$ip.\n");
        }
    }
    else {
        if ( not defined($hostName) or $hostName eq '' ) {
            $hasError = 1;
            print("ERROR: Must defined host name by option --hostname or define ip to hostname map by --ip2hostnamemap.\n");
        }
    }

    if ( $hasError != 0 ) {
        return $hasError;
    }

    if ( -f "/etc/hostname" ) {
        my $fh = IO::File->new('>/etc/hostname');
        if ( defined($fh) ) {
            print $fh ($hostName);
            $fh->close();
        }
    }

    $hasError = system("hostname '$hostName'");

    if ( $hasError == 0 and defined($hostNameMap) ) {
        my $processedMap = {};
        my $isChanged    = 0;
        my $fh           = IO::File->new("+<$filePath");
        if ( defined($fh) ) {
            my $line;
            while ( $line = $fh->getline() ) {
                if ( $line !~ /^\s*$/ and $line !~ /^\s*#/ ) {
                    my $tmpLine = $line;
                    $tmpLine =~ s/^\s*|\s*$//g;
                    my ( $ip, $name ) = split( /\s+/, $tmpLine, 2 );
                    my $newName = $hostNameMap->{$ip};
                    if ( defined($newName) and not $processedMap->{$ip} ) {

                        #delete( $confMap->{$ip} );
                        $processedMap->{$ip} = 1;
                        if ( $newName ne $name ) {
                            $isChanged = 1;
                            $line =~ s/\s+.*$/\t$newName/;
                            print("Replace: $tmpLine -> $line");
                        }
                        else {
                            print("NotChanged: $line");
                        }
                    }
                }
                $newContent = $newContent . $line;
            }

            my @srotedIps = sort { $hostNameMap->{$a} <=> $hostNameMap->{$b} } ( keys(%$hostNameMap) );

            #while ( my ( $ip, $name ) = each(%$confMap) ) {
            foreach my $ip (@srotedIps) {
                if ( $processedMap->{$ip} == 1 ) {
                    next;
                }
                my $name = $hostNameMap->{$ip};
                $isChanged  = 1;
                $newContent = $newContent . "$ip\t$name\n";
                print("Append: $ip\t$name\n");
            }

            if ( $isChanged == 1 ) {
                if ( $needBackup == 1 ) {
                    my $exitCode = backup($filePath);
                    if ( $exitCode != 0 ) {
                        print("ERROR: Backup file:$filePath failed, $!\n");
                        $hasError = 2;
                    }
                }

                if ( $hasError == 0 ) {
                    $fh->seek( 0, 0 );
                    $fh->truncate(0);
                    $fh->write( $newContent, length($newContent) );
                }
            }

            $fh->close();

            my $out = { hostsConf => $newContent };
            AutoExecUtils::saveOutput($out);

            if ( $hasError == 0 ) {
                if ( defined($hostName) and $hostName ne '' ) {
                    $hasError = system("hostname '$hostName'");
                }
            }
        }
        else {
            $hasError = 1;
            print("ERROR: Can not open file:$filePath, $!\n");
        }
    }

    return $hasError;
}

exit main();
